package com.sdu.utils.mybatis;

import java.sql.Connection;
import java.util.Properties;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;

import com.sdu.utils.mybatis.dialect.MysqlDialect;
import com.sdu.utils.mybatis.dialect.OracleDialect;

/**
 * 
 * 
 * Mybaits的拦截器
 *
 */
@Intercepts({
		@Signature(type = StatementHandler.class, method = "prepare", args = { Connection.class, Integer.class }) })
public class PaginationInterceptor implements Interceptor {

	protected static Log log = LogFactory.getLog(PaginationInterceptor.class);
	private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
	private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
	private static final ReflectorFactory REFLECTOR_FACTORY = new DefaultReflectorFactory();

	@Override
	public Object intercept(Invocation invocation) throws Throwable {
		StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
		BoundSql boundSql = statementHandler.getBoundSql();

		MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY,
				DEFAULT_OBJECT_WRAPPER_FACTORY, REFLECTOR_FACTORY);
		RowBounds rowBounds = (RowBounds) metaStatementHandler.getValue("delegate.rowBounds");
		if (rowBounds != null) {
			if (rowBounds != RowBounds.DEFAULT) {
				String originalSql = (String) metaStatementHandler.getValue("delegate.boundSql.sql");
				Configuration configuration = (Configuration) metaStatementHandler.getValue("delegate.configuration");
				Dialect.Type databaseType = null;
				try {
					databaseType = Dialect.Type
							.valueOf(configuration.getVariables().getProperty("dialect").toUpperCase());
				} catch (Exception e) {
					log.error("mybatis-config.xml中未设置数据库类型");
				}
				if (databaseType == null) {
					throw new RuntimeException(
							"the value of the dialect property in mybatis-config.xml is not defined : "
									+ configuration.getVariables().getProperty("dialect"));
				}
				Dialect dialect = null;
				switch (databaseType) {
				case ORACLE: // oracle 分页
					dialect = new OracleDialect();
					break;
				case MYSQL: // MySQL分页
					dialect = new MysqlDialect();
					break;
				}
				metaStatementHandler.setValue("delegate.boundSql.sql",
						dialect.getLimitString(originalSql, rowBounds.getOffset(), rowBounds.getLimit()));

				metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET);

				metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT);

				log.debug(" 生成分页SQL : " + boundSql.getSql());
			}

		}

		return invocation.proceed();

	}

	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	@Override
	public void setProperties(Properties arg0) {

	}

}
